import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { ObjectId } from 'bson';
import {
  NotifyQueueItem,
  notifyQueueModel,
} from 'src/notify/entities/notifyQueue.entity';
import { NotifyService } from 'src/notify/notify.service';
import { profileModel } from 'src/user/entity/profile.entity';
import { Profile } from 'src/user/interface/profile.interface';
import { ClockItem, clockModel, Clocks } from './entities/clock.entity';

@Injectable()
export class ClockService {
  async createClockAndClockItem(
    openid: string,
    name: string,
    target: number,
    tags: Array<string>,
  ) {
    const target_timestamp = target * 60 * 1000;
    const id = new ObjectId().toHexString();
    const clockItem: ClockItem = {
      id,
      name,
      target_timestamp,
      now_timestamp: 0,
      tags,
      playing: false,
    };
    let clock = null;
    clock = await this.findOne(openid);
    if (clock) {
      let commonClickItem = null;
      commonClickItem = await clockModel.findOne({
        openid,
        'clocks.name': name,
      });
      if (commonClickItem) {
        throw new HttpException(
          {
            message: '番茄钟名称重复',
          },
          HttpStatus.ACCEPTED,
        );
      }
      await clockModel.updateOne({ openid }, { $push: { clocks: clockItem } });
    } else {
      await clockModel.insertOne({
        openid,
        clocks: [clockItem],
      });
    }
    return {
      success: true,
      id,
    };
  }

  async setClockItem(
    openid: string,
    id: string,
    name: string,
    target: number,
    tags: Array<string>,
  ) {
    const clock = await this.findOne(openid);
    if (clock) {
      await clockModel.updateOne(
        { openid, 'clocks.id': id },
        {
          $set: {
            'clocks.$.name': name,
            'clocks.$.target': target,
            'clocks.$.tags': tags,
          },
        },
      );
    } else {
      // 本来就没有，就算成功了吧，不太会发生
    }
  }

  async findOne(openid: string) {
    const clocks = await clockModel.findOne<Clocks>({ openid });
    return clocks;
  }

  /**
   *
   * @param openid 用户id
   * @param id 任务id
   * 从clocks数组中找到任务id对应的任务
   */
  async findItem(openid: string, id: string): Promise<ClockItem | null> {
    const result = await clockModel.findOne<Clocks>({
      openid,
    });
    let clock = null;
    for (const val of result.clocks) {
      if (val.id === id) {
        clock = val;
        break;
      }
    }
    return clock;
  }

  async deleteClockItem(openid: string, id: string) {
    const result = await clockModel.updateOne(
      { openid },
      { $pull: { clocks: { id } } },
    );
    if (result.modifiedCount === 0) {
      throw new HttpException(
        {
          message: '该任务不存在或，已经被删除',
        },
        HttpStatus.ACCEPTED,
      );
    }
  }

  async deleteMultipleClockItem(openid: string, idArr: string[]) {
    const orArr = [];
    idArr.forEach((val) => {
      orArr.push({
        id: val,
      });
    });
    const result = await clockModel.updateMany(
      { openid },
      {
        $pull: { clocks: { $or: orArr } },
      },
    );
    if (result.modifiedCount === 0) {
      throw new HttpException(
        {
          message: '该任务不存在或，已经被删除',
        },
        HttpStatus.ACCEPTED,
      );
    }
  }

  /**
   *
   * @description 每次运行前端都需要更新一下唯一运行id
   */
  async startClock(openid: string, id: string) {
    const clocks = await clockModel.findOne<Clocks>({ openid });
    let target_timestamp = 0;
    let name = '';
    let tags = null;
    let isExist = false;
    for (const clockItem of clocks.clocks) {
      if (clockItem.id === id) {
        if (clockItem.playing === true) {
          throw new HttpException(
            {
              message: '已经开始运行',
            },
            HttpStatus.ACCEPTED,
          );
        }
        target_timestamp = clockItem.target_timestamp - clockItem.now_timestamp;
        name = clockItem.name;
        tags = clockItem.tags;
        isExist = true;
        break;
      }
    }
    if (!isExist) {
      throw new HttpException(
        {
          message: '该任务不存在',
        },
        HttpStatus.ACCEPTED,
      );
    }
    const notifyService = new NotifyService();
    await notifyService.addItem(openid, id, target_timestamp, name, tags);
    const result = await clockModel.updateOne(
      { openid, 'clocks.id': id },
      { $set: { 'clocks.$.playing': true } },
    );
    if (result.modifiedCount === 0) {
      throw new HttpException(
        {
          message: '该任务不存在',
        },
        HttpStatus.ACCEPTED,
      );
    }
  }

  async stopClock(openid: string, id: string) {
    const clocks = await this.findOne(openid);
    const profile = await profileModel.findOne<Profile>({ openid });
    let clockItem = null;
    if (clocks) {
      for (const v of clocks.clocks) {
        if (v.id === id) {
          clockItem = v;
          if (profile.allow_stop === false) {
            throw new HttpException(
              {
                message: '不允许停止',
              },
              HttpStatus.ACCEPTED,
            );
          }
          break;
        }
      }
    } else {
      throw new HttpException(
        {
          message: '该任务不存在',
        },
        HttpStatus.ACCEPTED,
      );
    }

    const notify = await notifyQueueModel.findOne<NotifyQueueItem>({
      openid,
    });
    const notifyService = new NotifyService();
    await notifyService.deleteItem(openid, id);
    const result = await clockModel.updateOne(
      { openid, 'clocks.id': id },
      {
        $set: {
          'clocks.$.playing': false,
          'clocks.$.now_timestamp':
            clockItem.now_timestamp + (Date.now() - notify.start_timestamp),
        },
      },
    );
    if (result.modifiedCount === 0) {
      throw new HttpException(
        {
          message: '该任务不存在',
        },
        HttpStatus.ACCEPTED,
      );
    }
  }
}
